import { GlTabs } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueRouter from 'vue-router';
import { shallowMount } from '@vue/test-utils';
import VulnerabilityReportTabs, {
  TAB_NAMES,
} from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_report_tabs.vue';
import VulnerabilityReportTab from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_report_tab.vue';
import {
  FIELD_PRESETS,
  FILTER_PRESETS,
} from 'ee/security_dashboard/components/shared/vulnerability_report/constants';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';

Vue.use(VueRouter);
const router = new VueRouter();

describe('Vulnerability report tabs component', () => {
  let wrapper;

  const createWrapper = ({ dashboardType = DASHBOARD_TYPES.PROJECT, slots } = {}) => {
    wrapper = shallowMount(VulnerabilityReportTabs, {
      router,
      provide: { dashboardType },
      stubs: { VulnerabilityReportTab },
      slots,
    });
  };

  const findTabsComponent = () => wrapper.findComponent(GlTabs);
  const findAllReportTabs = () => wrapper.findAllComponents(VulnerabilityReportTab);
  const findDevelopmentTab = () => findAllReportTabs().at(0);
  const findOperationalTab = () => findAllReportTabs().at(1);

  describe('tabs root component', () => {
    it.each`
      queryParam               | tabIndex
      ${undefined}             | ${0}
      ${TAB_NAMES.OPERATIONAL} | ${1}
    `(
      'shows tab with tabIndex $tabIndex when querystring is "$queryParam"',
      ({ queryParam, tabIndex }) => {
        router.replace({ query: { tab: queryParam } });
        createWrapper();

        expect(findTabsComponent().props('value')).toBe(tabIndex);
        expect(findDevelopmentTab().props('isActiveTab')).toBe(tabIndex === 0);
        expect(findOperationalTab().props('isActiveTab')).toBe(tabIndex === 1);
      },
    );

    it.each`
      tabIndex | queryParam
      ${0}     | ${undefined}
      ${1}     | ${TAB_NAMES.OPERATIONAL}
    `(
      'changes the tab when tabIndex $tabIndex is clicked and sets querystring to "$queryParam"',
      async ({ tabIndex, queryParam }) => {
        createWrapper();
        findTabsComponent().vm.$emit('input', tabIndex);
        await nextTick();

        expect(findTabsComponent().props('value')).toBe(tabIndex);
        expect(router.currentRoute.query.tab).toBe(queryParam);
      },
    );
  });

  describe('vulnerability report tabs', () => {
    it('shows 2 tabs', () => {
      createWrapper();
      expect(findAllReportTabs()).toHaveLength(2);
    });

    it.each`
      dashboardType               | expectedDevelopmentDropdowns          | expectedOperationalDropdowns
      ${DASHBOARD_TYPES.PROJECT}  | ${FILTER_PRESETS.DEVELOPMENT_PROJECT} | ${FILTER_PRESETS.OPERATIONAL_PROJECT}
      ${DASHBOARD_TYPES.GROUP}    | ${FILTER_PRESETS.DEVELOPMENT}         | ${FILTER_PRESETS.OPERATIONAL}
      ${DASHBOARD_TYPES.INSTANCE} | ${FILTER_PRESETS.DEVELOPMENT}         | ${FILTER_PRESETS.OPERATIONAL}
    `(
      'gets the expected props at the the $dashboardType level',
      ({ dashboardType, expectedDevelopmentDropdowns, expectedOperationalDropdowns }) => {
        createWrapper({ dashboardType });

        expect(findDevelopmentTab().props()).toMatchObject({
          title: wrapper.vm.$options.i18n.developmentTab,
          fields: FIELD_PRESETS.DEVELOPMENT,
          filterDropdowns: expectedDevelopmentDropdowns,
        });

        expect(findOperationalTab().props()).toMatchObject({
          title: wrapper.vm.$options.i18n.operationalTab,
          fields: FIELD_PRESETS.OPERATIONAL,
          filterDropdowns: expectedOperationalDropdowns,
          filterFn: wrapper.vm.transformFiltersOperational,
        });
      },
    );

    it('passes the slot content to the development tab', () => {
      createWrapper({
        slots: {
          'header-development': 'header slot content',
        },
      });

      expect(findDevelopmentTab().text()).toContain('header slot content');
    });

    it('shows the operational tab message in the operational tab', () => {
      createWrapper();

      expect(findOperationalTab().text()).toContain(wrapper.vm.$options.i18n.operationalTabMessage);
    });
  });
});
